
#include "Impl_Component.h"

_BeginNamespace(Radix)

/*
=================================================================
== ComponentSystem
=================================================================
*/
ComponentSystem::ComponentSystem()
	:mModules(),
	mComponents()
{}

ComponentSystem::~ComponentSystem()
{
	this->unloadModules();
}

bool ComponentSystem::loadModule(const String& name)
{
	if(mModules.find(name) != mModules.end())
		return false;

	Module* module = new Module(name);
	if(! module->load())
	{
		module->unload();
		delete module;
		return false;
	}

	InitComponentModuleFunc initFunc = (InitComponentModuleFunc)module->getSymbol(gskInitComponentFuncName);
	ExitComponentModuleFunc exitFunc = (ExitComponentModuleFunc)module->getSymbol(gskExitComponentFuncName);
	if(initFunc == nullptr || exitFunc == nullptr)
	{
		module->unload();
		delete module;
		return false;
	}

	if(! initFunc(this))
	{
		exitFunc(this);
		module->unload();
		delete module;
		return false;
	}

	ComponentModule compModule;
	compModule.mModule = module;
	compModule.mInitFunc = initFunc;
	compModule.mExitFunc = exitFunc;
	mModules[name] = compModule;

	return true;
}

void ComponentSystem::unloadModule(const String& name)
{
	auto moduleIter = mModules.find(name);
	if(moduleIter == mModules.end())
		return;

	ComponentModule& compModule = moduleIter->second;
	if(compModule.mExitFunc != nullptr)
	{
		compModule.mExitFunc(this);
	}
	if(compModule.mModule != nullptr)
	{
		compModule.mModule->unload();
		delete compModule.mModule;
	}

	mModules.erase(moduleIter);	
}

void ComponentSystem::unloadModules()
{
	if(mModules.empty())
		return;

	auto moduleIter = mModules.begin();
	while(moduleIter != mModules.end())
	{
		ComponentModule& compModule = moduleIter->second;
		if(compModule.mExitFunc != nullptr)
		{
			compModule.mExitFunc(this);
		}
		if(compModule.mModule != nullptr)
		{
			compModule.mModule->unload();
			delete compModule.mModule;
		}
		++ moduleIter;
	}

	mModules.clear();
}

bool ComponentSystem::attachComponent(IComponent* component)
{
	if(component == nullptr)
		return false;
	const String& name = component->name();
	if(this->containsComponent(name))
		return false;
	mComponents[name] = component;
	return true;
}

void ComponentSystem::detachComponent(IComponent* component)
{
	if(component == nullptr)
		return;
	const String& name = component->name();
	auto compIter = mComponents.find(name);
	if(compIter == mComponents.end())
		return;
	mComponents.erase(compIter);
}

bool ComponentSystem::containsComponent(const String& name)
{
	return mComponents.find(name) != mComponents.end();
}

IComponent* ComponentSystem::selectComponent(const String& name)
{
	auto compIter = mComponents.find(name);
	if(compIter == mComponents.end())
		return nullptr;
	return compIter->second;
}

_EndNamespace(Radix)
